from abc import ABC, abstractmethod
from typing import List, Any
import time


class TextCommand(ABC):
    """命令模式的抽象基类"""

    @abstractmethod
    def execute(self):
        """执行命令"""
        pass

    @abstractmethod
    def undo(self):
        """撤销命令"""
        pass

    @abstractmethod
    def redo(self):
        """重做命令"""
        pass


class InsertTextCommand(TextCommand):
    """插入文本命令"""

    def __init__(self, document, position: int, text: str):
        self.document = document
        self.position = position
        self.text = text
        self.timestamp = time.time()

    def execute(self):
        """执行插入操作"""
        self.document._insert_text(self.position, self.text)

    def undo(self):
        """撤销插入操作"""
        self.document._delete_text(self.position, len(self.text))

    def redo(self):
        """重做插入操作"""
        self.execute()

    def __str__(self):
        return f"Insert '{self.text}' at position {self.position}"


class DeleteTextCommand(TextCommand):
    """删除文本命令"""

    def __init__(self, document, position: int, text: str):
        self.document = document
        self.position = position
        self.text = text  # 保存被删除的文本
        self.timestamp = time.time()

    def execute(self):
        """执行删除操作"""
        self.document._delete_text(self.position, len(self.text))

    def undo(self):
        """撤销删除操作"""
        self.document._insert_text(self.position, self.text)

    def redo(self):
        """重做删除操作"""
        self.execute()

    def __str__(self):
        return f"Delete '{self.text}' from position {self.position}"


class ReplaceTextCommand(TextCommand):
    """替换文本命令"""

    def __init__(self, document, position: int, old_text: str, new_text: str):
        self.document = document
        self.position = position
        self.old_text = old_text
        self.new_text = new_text
        self.timestamp = time.time()

    def execute(self):
        """执行替换操作"""
        self.document._delete_text(self.position, len(self.old_text))
        self.document._insert_text(self.position, self.new_text)

    def undo(self):
        """撤销替换操作"""
        self.document._delete_text(self.position, len(self.new_text))
        self.document._insert_text(self.position, self.old_text)

    def redo(self):
        """重做替换操作"""
        self.execute()

    def __str__(self):
        return f"Replace '{self.old_text}' with '{self.new_text}' at position {self.position}"


class CommandHistory:
    """命令历史管理器"""

    def __init__(self, max_history_size: int = 100):
        self.undo_stack: List[TextCommand] = []
        self.redo_stack: List[TextCommand] = []
        self.max_history_size = max_history_size

    def push(self, command: TextCommand):
        """添加新命令到历史记录"""
        self.undo_stack.append(command)
        self.redo_stack.clear()  # 新的命令会清除重做栈

        # 如果超过最大历史记录大小，移除最旧的命令
        if len(self.undo_stack) > self.max_history_size:
            self.undo_stack.pop(0)

    def can_undo(self) -> bool:
        """检查是否可以撤销"""
        return len(self.undo_stack) > 0

    def can_redo(self) -> bool:
        """检查是否可以重做"""
        return len(self.redo_stack) > 0

    def undo(self) -> TextCommand:
        """撤销上一个命令"""
        if not self.can_undo():
            raise ValueError("没有可撤销的命令")

        command = self.undo_stack.pop()
        command.undo()
        self.redo_stack.append(command)
        return command

    def redo(self) -> TextCommand:
        """重做最后一个撤销的命令"""
        if not self.can_redo():
            raise ValueError("没有可重做的命令")

        command = self.redo_stack.pop()
        command.redo()
        self.undo_stack.append(command)
        return command

    def clear(self):
        """清空历史记录"""
        self.undo_stack.clear()
        self.redo_stack.clear()

    def get_history_info(self) -> dict:
        """获取历史记录信息"""
        return {
            'undo_count': len(self.undo_stack),
            'redo_count': len(self.redo_stack),
            'max_size': self.max_history_size
        }


class TextDocument:
    """文本文档类"""

    def __init__(self):
        self.content = ""
        self.history = CommandHistory()

    def _insert_text(self, position: int, text: str):
        """内部方法：插入文本（不记录历史）"""
        self.content = self.content[:position] + text + self.content[position:]

    def _delete_text(self, position: int, length: int):
        """内部方法：删除文本（不记录历史）"""
        self.content = self.content[:position] + self.content[position + length:]

    def insert_text(self, position: int, text: str):
        """插入文本（记录历史）"""
        if position < 0 or position > len(self.content):
            raise ValueError("位置超出范围")

        command = InsertTextCommand(self, position, text)
        command.execute()
        self.history.push(command)

    def delete_text(self, position: int, length: int):
        """删除文本（记录历史）"""
        if position < 0 or position + length > len(self.content):
            raise ValueError("位置或长度超出范围")

        deleted_text = self.content[position:position + length]
        command = DeleteTextCommand(self, position, deleted_text)
        command.execute()
        self.history.push(command)

    def replace_text(self, position: int, length: int, new_text: str):
        """替换文本（记录历史）"""
        if position < 0 or position + length > len(self.content):
            raise ValueError("位置或长度超出范围")

        old_text = self.content[position:position + length]
        command = ReplaceTextCommand(self, position, old_text, new_text)
        command.execute()
        self.history.push(command)

    def undo(self):
        """撤销上一个操作"""
        if self.history.can_undo():
            command = self.history.undo()
            print(f"撤销: {command}")
        else:
            print("没有可撤销的操作")

    def redo(self):
        """重做上一个撤销的操作"""
        if self.history.can_redo():
            command = self.history.redo()
            print(f"重做: {command}")
        else:
            print("没有可重做的操作")

    def get_content(self) -> str:
        """获取文档内容"""
        return self.content

    def set_content(self, content: str):
        """设置文档内容（不记录历史，用于初始化）"""
        self.content = content
        self.history.clear()

    def get_document_info(self) -> dict:
        """获取文档信息"""
        return {
            'content_length': len(self.content),
            'history_info': self.history.get_history_info()
        }


class TextEditor:
    """文本编辑器主类"""

    def __init__(self):
        self.document = TextDocument()
        self.is_running = False

    def display_status(self):
        """显示编辑器和文档状态"""
        print("\n" + "=" * 50)
        print("文本编辑器")
        print("=" * 50)
        print(f"文档内容: '{self.document.get_content()}'")
        print(f"文档长度: {len(self.document.get_content())} 字符")

        history_info = self.document.get_document_info()['history_info']
        print(f"可撤销操作: {history_info['undo_count']}")
        print(f"可重做操作: {history_info['redo_count']}")
        print("=" * 50)

    def display_help(self):
        """显示帮助信息"""
        print("\n可用命令:")
        print("  i [位置] [文本]  - 在指定位置插入文本")
        print("  d [位置] [长度]  - 从指定位置删除指定长度的文本")
        print("  r [位置] [长度] [新文本] - 替换文本")
        print("  u                - 撤销")
        print("  r                - 重做")
        print("  c                - 清空文档")
        print("  s                - 显示状态")
        print("  h                - 显示帮助")
        print("  q                - 退出")

    def run(self):
        """运行文本编辑器"""
        self.is_running = True
        print("欢迎使用文本编辑器！")
        self.display_help()

        while self.is_running:
            try:
                command = input("\n请输入命令: ").strip().split()

                if not command:
                    continue

                cmd_type = command[0].lower()

                if cmd_type == 'q':
                    self.is_running = False
                    print("再见！")

                elif cmd_type == 'i' and len(command) >= 3:
                    position = int(command[1])
                    text = ' '.join(command[2:])
                    self.document.insert_text(position, text)
                    self.display_status()

                elif cmd_type == 'd' and len(command) >= 3:
                    position = int(command[1])
                    length = int(command[2])
                    self.document.delete_text(position, length)
                    self.display_status()

                elif cmd_type == 'r' and len(command) >= 4:
                    position = int(command[1])
                    length = int(command[2])
                    new_text = ' '.join(command[3:])
                    self.document.replace_text(position, length, new_text)
                    self.display_status()

                elif cmd_type == 'u':
                    self.document.undo()
                    self.display_status()

                elif cmd_type == 'r':
                    self.document.redo()
                    self.display_status()

                elif cmd_type == 'c':
                    self.document.set_content("")
                    print("文档已清空")
                    self.display_status()

                elif cmd_type == 's':
                    self.display_status()

                elif cmd_type == 'h':
                    self.display_help()

                else:
                    print("无效命令，请输入 'h' 查看帮助")

            except ValueError as e:
                print(f"错误: {e}")
            except Exception as e:
                print(f"发生错误: {e}")


# 演示使用
def main():
    """演示文本编辑器的撤销功能"""
    print("=== 文本编辑器撤销功能演示 ===")

    editor = TextEditor()
    document = editor.document

    # 初始内容
    document.set_content("Hello World")
    print(f"初始内容: '{document.get_content()}'")

    # 执行一些操作
    print("\n1. 在位置6插入文本")
    document.insert_text(6, "Beautiful ")
    print(f"插入后: '{document.get_content()}'")

    print("\n2. 替换文本")
    document.replace_text(0, 5, "Hi")
    print(f"替换后: '{document.get_content()}'")

    print("\n3. 删除文本")
    document.delete_text(2, 1)
    print(f"删除后: '{document.get_content()}'")

    # 演示撤销
    print("\n4. 撤销操作")
    document.undo()
    print(f"撤销后: '{document.get_content()}'")

    document.undo()
    print(f"再次撤销: '{document.get_content()}'")

    # 演示重做
    print("\n5. 重做操作")
    document.redo()
    print(f"重做后: '{document.get_content()}'")

    document.redo()
    print(f"再次重做: '{document.get_content()}'")

    # 显示最终状态
    print("\n最终状态:")
    info = document.get_document_info()
    print(f"文档内容: '{document.get_content()}'")
    print(f"历史记录: {info['history_info']}")


if __name__ == "__main__":
    # 运行演示
    main()